package api

// api 具体的内部逻辑

import (
	"a_plus_station/commons"
	"a_plus_station/dto_out"
	"a_plus_station/forms"
	"a_plus_station/global"
	"a_plus_station/middlewares"
	"a_plus_station/models"
	"a_plus_station/tables"
	vali_tran "a_plus_station/validator"
	"crypto/sha512"
	"fmt"
	"github.com/anaskhan96/go-password-encoder"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	jsoniter "github.com/json-iterator/go"
	"github.com/olivere/elastic/v7"
	"go.uber.org/zap"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"
)

// 密码登陆
func PassWordLogin(ctx *gin.Context) {
	// 表单验证 获取表单信息
	passwordLoginForm := forms.PassWordLoginForm{}
	err := ctx.ShouldBind(&passwordLoginForm)
	zap.S().Debugf("登陆用户信息: %v", passwordLoginForm)
	// 返回表单验证错误信息
	if err != nil {
		vali_tran.HandleValidatorError(ctx, err)
		return
	}

	// 验证码校验 设置了一个万能码 登录就不用了
	//if passwordLoginForm.Captcha != commons.BaseCaptcha && passwordLoginForm.CaptchaId != commons.BaseCaptchaId{
	//	if !store.Verify(passwordLoginForm.CaptchaId,passwordLoginForm.Captcha,true){
	//		ctx.JSON(http.StatusBadRequest,gin.H{
	//			"captcha":"验证码错误",
	//		})
	//		return
	//	}
	//}

	var user tables.User
	result := global.DB.Where(&tables.User{Email: passwordLoginForm.Email}).First(&user)
	// 如果用户不存在
	if result.RowsAffected == 0 {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "用户不存在",
		})
		return
	}
	if result.Error != nil {
		ctx.JSON(http.StatusInternalServerError, result.Error)
		return
	}

	// 校验密码
	options := &password.Options{SaltLen: 16, Iterations: 100, KeyLen: 32, HashFunction: sha512.New}
	passwordInfo := strings.Split(user.Password, "$")
	//fmt.Println(passwordInfo) // [" " pbkdf2-sha512 968mcWVPSo 535031b82b89df451eb670f18971e2594a5a2fd713e0595c84e8d33e40d35478]
	check := password.Verify(passwordLoginForm.Password, passwordInfo[2], passwordInfo[3], options)
	if !check {
		ctx.JSON(http.StatusForbidden, gin.H{
			"msg": "密码错误",
		})
		return
	}

	// 生成token
	j := middlewares.NewJWT()
	claims := models.CustomClaims{
		ID: user.ID,
		StandardClaims: jwt.StandardClaims{ // 可选参数
			NotBefore: time.Now().Unix(),           // 签名的生效时间
			ExpiresAt: time.Now().Unix() + 60*60*8, // 八个小时过期
			Issuer:    commons.Issuer,
		},
	}
	token, err := j.CreateToken(claims)

	// 添加用户的信息 和颁发的 token
	userInfo := dto_out.UserInfo{
		ID:        user.ID,
		Email:     user.Email,
		FirstName: user.FirstName,
		LastName:  user.LastName,
	}
	// 检查mobile
	if user.Mobile != nil {
		userInfo.Mobile = *user.Mobile
	} else {
		userInfo.Mobile = ""
	}

	outputUserInfo := dto_out.UserTokenInfo{
		UserInfo: userInfo,
		Token:    token,
	}
	// 添加用户的信息 和颁发的 token
	ctx.JSON(http.StatusOK, gin.H{
		"msg":  "用户登陆成功",
		"data": outputUserInfo,
	})
}

// 注册
func Register(ctx *gin.Context) {
	// 用户注册
	RegisterForm := forms.RegisterForm{}
	zap.S().Debugf("注册信息%v", RegisterForm)
	err := ctx.ShouldBind(&RegisterForm)
	if err != nil {
		vali_tran.HandleValidatorError(ctx, err)
		return
	}

	// 验证码校验 设置了一个万能码
	//if RegisterForm.Captcha != commons.BaseCaptcha && RegisterForm.CaptchaId != commons.BaseCaptchaId {
	//	if !store.Verify(RegisterForm.CaptchaId, RegisterForm.Captcha, true) {
	//		ctx.JSON(http.StatusBadRequest, gin.H{
	//			"captcha": "验证码错误",
	//		})
	//		return
	//	}
	//}

	// 先查询用户是否存在
	var user tables.User
	result := global.DB.Where(tables.User{Email: RegisterForm.Email}).First(&user)
	if result.RowsAffected == 1 {
		ctx.JSON(http.StatusForbidden, gin.H{
			"msg": "用户已存在",
		})
		return
	}

	user.Email = RegisterForm.Email
	user.FirstName = RegisterForm.FirstName
	user.LastName = RegisterForm.LastName

	//birthday := time.Unix(int64(req.Birthday),0)
	//user.Name = req.Name
	//user.Birthday = &birthday

	// 密码加密
	options := &password.Options{SaltLen: 16, Iterations: 100, KeyLen: 32, HashFunction: sha512.New}
	salt, encodedPwd := password.Encode(RegisterForm.Password, options)
	user.Password = fmt.Sprintf("$%s$%s$%s", "pbkdf2-sha512", salt, encodedPwd)

	// 创建用户
	tx := global.DB.Begin()
	result = tx.Create(&user) // 通过数据的指针来创建
	if result.Error != nil {
		//return nil,status.Errorf(codes.Internal,result.Error.Error()) // .Error()会帮我们转换成error
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "用户注册失败",
		})
		tx.Rollback()
		return
	}
	tx.Commit()
	// 生成token
	j := middlewares.NewJWT()
	claims := models.CustomClaims{
		ID: user.ID,
		StandardClaims: jwt.StandardClaims{ // 可选参数
			NotBefore: time.Now().Unix(),           // 签名的生效时间
			ExpiresAt: time.Now().Unix() + 60*60*8, // 八个小时过期
			Issuer:    commons.Issuer,
		},
	}
	token, err := j.CreateToken(claims)

	if err != nil {
		zap.S().Infof("%s token产生失败", err.Error())
		ctx.JSON(http.StatusInternalServerError, map[string]string{
			"msg": "token产生失败",
		})
		return
	}

	userInfo := dto_out.UserInfo{
		ID:        user.ID,
		Email:     user.Email,
		FirstName: user.FirstName,
		LastName:  user.LastName,
	}
	outputUserInfo := dto_out.UserTokenInfo{
		UserInfo: userInfo,
		Token:    token,
	}
	// 添加用户的信息 和颁发的 token
	ctx.JSON(http.StatusOK, gin.H{
		"msg":  "用户注册成功",
		"data": outputUserInfo,
	})
}

// 获取当前时间的0点时间
func Str2Time(formatTimeStr string) time.Time {
	// 模板
	timeLayout := "2006-01-02"
	loc, _ := time.LoadLocation("Local")
	theTime, _ := time.ParseInLocation(timeLayout, formatTimeStr, loc) //使用模板在对应时区转化为time.time类型

	return theTime
}

// 更新 user
func UpdateUser(ctx *gin.Context) {
	// 用户注册
	var UpdateUserForm forms.UpdateUserForm
	zap.S().Debugf("登陆注册%v", UpdateUserForm)
	err := ctx.ShouldBind(&UpdateUserForm)
	if err != nil {
		vali_tran.HandleValidatorError(ctx, err)
		return
	}
	var user tables.User
	userId, _ := ctx.Get("userId")
	result := global.DB.First(&user, userId)
	if result.RowsAffected == 0 {
		zap.S().Infof("%s 用户不存在", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "用户不存在",
		})
		return
	}

	if UpdateUserForm.Email == "" && UpdateUserForm.LastName == "" && UpdateUserForm.FirstName == "" && UpdateUserForm.Mobile == "" {
		zap.S().Infof("更新数据都为空")
		ctx.JSON(http.StatusOK, gin.H{
			"msg": "用户信息更新成功",
		})
		return
	}

	if UpdateUserForm.Email != "" {
		emailRegexPattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`

		// Compile the regular expression
		ok, _ := regexp.MatchString(emailRegexPattern, UpdateUserForm.Email)
		// 使用正则表达式判断是否合法
		if !ok {
			//{0} 非法的邮箱
			zap.S().Infof("%s 非法的邮箱", err.Error())
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"msg": "非法的邮箱",
			})
			return
		}
		user.Email = UpdateUserForm.Email
	}

	if UpdateUserForm.LastName != "" {
		user.LastName = UpdateUserForm.LastName
	}

	if UpdateUserForm.FirstName != "" {
		user.FirstName = UpdateUserForm.FirstName
	}

	if UpdateUserForm.Address != "" {
		user.Address = UpdateUserForm.Address
	}

	if UpdateUserForm.Mobile != "" {
		regexPattern := `\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}`

		// Compile the regular expression
		ok, _ := regexp.MatchString(regexPattern, UpdateUserForm.Mobile)
		// 使用正则表达式判断是否合法
		if !ok {
			//{0} 非法的邮箱
			zap.S().Infof("%s 非法的手机号", err.Error())
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"msg": "非法的手机号",
			})
			return
		}
		user.Mobile = &UpdateUserForm.Mobile
	}

	tx := global.DB.Begin()
	result = tx.Save(&user)
	if result.Error != nil {
		zap.S().Infof("%s 用户信息更新失败", err.Error())
		ctx.JSON(http.StatusInternalServerError, map[string]string{
			"msg": "用户信息更新失败",
		})
		tx.Rollback()
		return
	}
	tx.Commit()
	//return &empty.Empty{},nil
	ctx.JSON(http.StatusOK, map[string]string{
		"msg": "用户信息更新成功",
	})
	return
}

// 通过token获取 user信息
func GetUser(ctx *gin.Context) {
	var user tables.User
	userId, _ := ctx.Get("userId")
	result := global.DB.First(&user, userId)

	if result.RowsAffected == 0 {
		zap.S().Infof("%s 用户不存在", result.Error)
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "用户不存在",
		})
		return
	}

	output := dto_out.UserInfo{
		ID:        user.ID,
		FirstName: user.FirstName,
		LastName:  user.LastName,
		Email:     user.Email,
		Address:   user.Address,
		Mobile:    *user.Mobile,
	}
	// 检查mobile
	if user.Mobile != nil {
		output.Mobile = *user.Mobile
	} else {
		output.Mobile = ""
	}

	// 添加用户的信息 和颁发的 token
	ctx.JSON(http.StatusOK, gin.H{
		"msg":  "获取用户信息成功",
		"data": output,
	})
	return
}

// 获取我的关注
func GetMyCollect(ctx *gin.Context) {
	collectForm := forms.CollectForm{}
	if err := ctx.ShouldBind(&collectForm); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 设置分页默认值
	if collectForm.Page <= 0 {
		collectForm.Page = 1
	}
	if collectForm.PageSize <= 0 || collectForm.PageSize > 100 {
		collectForm.PageSize = 20 // 限制最大100条/页
	}

	// 获取用户ID
	userID, exists := ctx.Get("userId")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
		return
	}

	userIDInt, ok := userID.(int32)
	if !ok {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "用户ID格式错误"})
		return
	}

	// 分页获取收藏商品ID
	collectIDs, totalCollects, err := global.CollectCache.GetUserCollectsPaged(
		global.DB,
		userIDInt,
		collectForm.Page,
		collectForm.PageSize,
	)

	if err != nil {
		log.Printf("分页获取收藏失败: %v", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "查询收藏失败"})
		return
	}

	// 将收藏商品ID转换为int64
	// 将收藏商品ID转换为 []interface{} 类型
	var collectIDsInterface []interface{}
	for _, id := range collectIDs {
		collectIDsInterface = append(collectIDsInterface, id)
	}

	// 使用带缓存的ES查询
	goodsSearchForm := forms.GoodsSearch{
		KeyWords: collectForm.Keyword,
		Sort:     true,
		Page:     collectForm.Page,
	}

	if goodsSearchForm.SortField != "" {
		fieldIsIn := in(goodsSearchForm.SortField, []string{"shop_min_price", "shop_max_price", "created_at", "click", "score", "is_new", "is_hot"})
		if !fieldIsIn {
			zap.S().Infof("%s 排序字段无效", goodsSearchForm.SortField)
			ctx.JSON(http.StatusBadRequest, gin.H{
				"msg": "排序字段无效",
			})
			return
		}
	}

	q := elastic.NewBoolQuery()

	// 关键修改1：添加收藏商品ID过滤条件
	if len(collectIDsInterface) > 0 {
		q = q.Filter(elastic.NewTermsQuery("goods_id", collectIDsInterface...))
	} else {
		// 如果没有收藏商品，直接返回空结果
		GoodsOut := dto_out.GoodsLiOut{
			GoodsLiInfo: []dto_out.GoodsLiInfo{},
			Count:       0,
		}
		ctx.JSON(http.StatusOK, gin.H{
			"msg":    "查询成功",
			"data":   GoodsOut,
			"status": 200,
		})
		return
	}

	if goodsSearchForm.KeyWords != "" {
		KeyWords := SearchKeyWordsFormat(goodsSearchForm.KeyWords)
		zap.S().Infof("%s 搜索关键词", KeyWords)
		q = q.Must(elastic.NewMultiMatchQuery(KeyWords, "name", "key_words", "goods_desc", "goods_id"))
	}

	if goodsSearchForm.CategoryID > 0 {
		q = q.Filter(elastic.NewTermQuery("category_id", goodsSearchForm.CategoryID))
	}

	if goodsSearchForm.ShopMinPrice > 0 {
		q = q.Filter(elastic.NewRangeQuery("shop_min_price").Gte(goodsSearchForm.ShopMinPrice))
	}

	if goodsSearchForm.ShopMaxPrice > 0 {
		q = q.Filter(elastic.NewRangeQuery("shop_max_price").Lte(goodsSearchForm.ShopMaxPrice))
	}

	zap.S().Infof("%s es搜索", q)

	switch {
	case goodsSearchForm.Page <= 0:
		goodsSearchForm.Page = 1
	case goodsSearchForm.Page >= 999:
		goodsSearchForm.Page = 999
	}

	switch {
	case goodsSearchForm.PageSize > 28:
		goodsSearchForm.PageSize = 28
	case goodsSearchForm.PageSize <= 0:
		goodsSearchForm.PageSize = 28
	}

	offset := (goodsSearchForm.Page - 1) * goodsSearchForm.PageSize

	esSearch := global.EsClient.Search().Index(models.EsGoods{}.GetIndexName()).Query(q)
	if goodsSearchForm.SortField == "" {
		esSearch = esSearch.Sort("created_at", false) // false 降序
	} else {
		esSearch = esSearch.Sort(goodsSearchForm.SortField, goodsSearchForm.Sort)
	}

	re, err := esSearch.Sort("created_at", false).From(int(offset)).Size(int(goodsSearchForm.PageSize)).Do(ctx)
	if err != nil {
		zap.S().Infof("%s es错误", err.Error())
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "es错误",
		})
		return
	}

	src, err := q.Source()
	if err != nil {
		zap.S().Infof("%s es查询错误", err.Error())
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "es查询错误",
		})
		return
	}
	data, err := jsoniter.MarshalIndent(src, "", "  ")
	if err != nil {
		zap.S().Infof("%s es序列化错误", err.Error())
		ctx.JSON(http.StatusBadRequest, gin.H{
			"msg": "es序列化错误",
		})
		return
	}
	zap.S().Infof("%s es搜索", string(data))

	// 关键修改2：使用收藏总数而不是ES匹配总数
	total := totalCollects // 使用收藏总数作为分页依据
	zap.S().Infof("%d es搜索 共计:", total)

	var goodsLi []dto_out.GoodsLiInfo
	for _, v := range re.Hits.Hits {
		goods := models.EsGoods{}
		jsoniter.Unmarshal(v.Source, &goods)
		goodsLiInfo := dto_out.GoodsLiInfo{
			GoodsID:      goods.GoodsID,
			Name:         goods.Name,
			GoodsDesc:    goods.GoodsDesc,
			Score:        goods.Score,
			ShopMinPrice: goods.ShopMinPrice,
			ShopMaxPrice: goods.ShopMaxPrice,
			MainPicture:  goods.MainPicture,
			CreateAt:     goods.CreatedAt,
		}
		goodsLi = append(goodsLi, goodsLiInfo)
	}

	// 创建映射：goods_id -> 在原始数组中的索引
	indexMap := make(map[string]int)
	for i, id := range collectIDs {
		indexMap[id] = i
	}

	// 分离数据：存在于原始数组中的元素和不存在元素
	var present, absent []dto_out.GoodsLiInfo
	for _, item := range goodsLi {
		if _, exists := indexMap[item.GoodsID]; exists {
			present = append(present, item)
		} else {
			absent = append(absent, item)
		}
	}

	GoodsOut := dto_out.GoodsLiOut{
		GoodsLiInfo: present,
		Count:       int32(total), // 使用收藏总数
	}
	ctx.JSON(http.StatusOK, gin.H{
		"msg":    "查询成功",
		"data":   GoodsOut,
		"status": 200,
	})
	return
}

// 点击收藏和取消收藏
func AddCollect(ctx *gin.Context) {
	userId, _ := ctx.Get("userId")
	userIdInt, ok := userId.(int32)
	if !ok {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "收藏失败",
		})
		return
	}
	GoodsCollect := forms.GoodsCollect{}
	err := ctx.ShouldBind(&GoodsCollect)
	if err != nil {
		vali_tran.HandleValidatorError(ctx, err)
		return
	}

	collect := tables.Collect{
		UserID:  userIdInt,
		GoodsID: GoodsCollect.GoodsID,
	}
	collected, err := global.CollectCache.IsCollected(userIdInt, GoodsCollect.GoodsID)
	if err != nil || collected != false {
		zap.S().Infof("%s 增加收藏失败")
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "增加收藏失败",
		})
		return
	}

	Goods := tables.Goods{}
	goodsResult := global.DB.Where(&tables.Goods{GoodsID: GoodsCollect.GoodsID}).First(&Goods)
	if goodsResult.RowsAffected == 0 {
		ctx.JSON(http.StatusForbidden, gin.H{
			"msg": "商品不存在",
		})
		return
	}

	tx := global.DB.Begin()
	result := tx.WithContext(ctx).Create(&collect)
	if result.Error != nil {
		zap.S().Infof("%s 增加收藏失败", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "增加收藏失败",
		})
		tx.Rollback()
		return
	}
	err = global.CollectCache.AddCollect(userIdInt, GoodsCollect.GoodsID)
	if err != nil {
		zap.S().Infof("%s 增加收藏失败", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "增加收藏失败",
		})
		tx.Rollback()
		return
	}

	tx.Commit()
	ctx.JSON(http.StatusOK, gin.H{
		"msg":    "增加收藏成功",
		"status": 200,
	})
	return
}

// 点击收藏和取消收藏
func RemoveCollect(ctx *gin.Context) {
	userId, _ := ctx.Get("userId")
	userIdInt, ok := userId.(int32)
	if !ok {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "取消收藏失败",
		})
		return
	}
	GoodsCollect := forms.GoodsCollect{}
	err := ctx.ShouldBind(&GoodsCollect)
	if err != nil {
		vali_tran.HandleValidatorError(ctx, err)
		return
	}
	collected, err := global.CollectCache.IsCollected(userIdInt, GoodsCollect.GoodsID)
	if err != nil || collected != true {
		zap.S().Infof("%s 取消收藏失败")
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "取消收藏失败",
		})
		return
	}

	Goods := tables.Goods{}
	goodsResult := global.DB.Where(&tables.Goods{GoodsID: GoodsCollect.GoodsID}).First(&Goods)
	if goodsResult.RowsAffected == 0 {
		ctx.JSON(http.StatusForbidden, gin.H{
			"msg": "商品不存在",
		})
		return
	}

	tx := global.DB.Begin()
	result := tx.WithContext(ctx).Where("user_id = ? AND goods_id = ?", userIdInt, GoodsCollect.GoodsID).Delete(&tables.Collect{})
	if result.Error != nil {
		zap.S().Infof("%s 取消收藏失败", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "取消收藏失败",
		})
		tx.Rollback()
		return
	}
	err = global.CollectCache.RemoveCollect(userIdInt, GoodsCollect.GoodsID)
	if err != nil {
		zap.S().Infof("%s 取消收藏失败", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "取消收藏失败",
		})
		tx.Rollback()
		return
	}

	tx.Commit()
	ctx.JSON(http.StatusOK, gin.H{
		"msg":    "取消收藏成功",
		"status": 200,
	})
	return
}
